package com.tqz.juc.aqs;

import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * {@link Semaphore}信号量测试。如果资源数量设置了1，那么就是独占锁，如果资源数量设置了大于1，那么就是共享锁。
 * 它同时也实现了公平锁和非公平锁。
 * 实现了AQS的共享模式，允许多个线程共享锁状态。
 *
 * <p>应用场景：限流、资源池。
 *
 * @author tianqingzhao
 * @since 2022/2/5 18:02
 */
public class SemaphoreTest {

    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2);
        Semaphore semaphore2 = new Semaphore(3);
        for (int i = 0; i < 10; i++) {
            new Thread(new Task(semaphore, "tqz+" + i)).start();

            new Thread(new Task2(semaphore2, "tqz+" + i)).start();
        }
    }

    static class Task extends Thread {

        Semaphore semaphore;

        public Task(Semaphore semaphore, String tname) {
            super(tname);
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                // 获取公共资源，获取几个就要释放几个
                semaphore.acquire();

                System.out.println(
                        Thread.currentThread().getName() + ":aquire() at time:" + System.currentTimeMillis());
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                semaphore.release();
            }
        }
    }

    static class Task2 extends Thread {

        Semaphore semaphore;

        public Task2(Semaphore semaphore, String tname) {
            super(tname);
            this.semaphore = semaphore;
        }

        @Override
        public void run() {
            try {
                // 指定时间尝试获取信号量，没有拿到就降级，hystrix原理
                // 500除以300，等于1余200，所以能通过Semaphore的2次，即6次
                if (semaphore.tryAcquire(500, TimeUnit.MILLISECONDS)) {
                    System.out.println("请求通过");
                    Thread.sleep(300);
                } else {
                    ratelimit();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //释放公共资源
                semaphore.release();
            }
        }

        public void ratelimit() {
            System.out.println("请求被限流");
        }
    }
}
